/*-------------------------------------------------------------------------
 *
 * be-gssapi-common.c
 *     GSSAPI身份验证和加密的公共代码
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *       src/backend/libpq/be-gssapi-common.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "libpq/be-gssapi-common.h"

/*
 * 获取特定类型的所有错误并附加到 "s"（大小为 len 的缓冲区）。
 * 如果我们获得多个字符串，用空格分隔它们。
 * 对 GSS_CODE 调用一次，对 MECH_CODE 调用一次。
 */
static void fc_pg_GSS_error_int(char *fc_s, size_t fc_len, OM_uint32 fc_stat, int fc_type)
{
	gss_buffer_desc fc_gmsg;
	size_t		fc_i = 0;
	OM_uint32	fc_lmin_s,
				fc_msg_ctx = 0;

	do
	{
		if (gss_display_status(&fc_lmin_s, fc_stat, fc_type, GSS_C_NO_OID,
							   &fc_msg_ctx, &fc_gmsg) != GSS_S_COMPLETE)
			break;
		if (fc_i > 0)
		{
			if (fc_i < fc_len)
				fc_s[fc_i] = ' ';
			fc_i++;
		}
		if (fc_i < fc_len)
			memcpy(fc_s + fc_i, fc_gmsg.value, Min(fc_len - fc_i, fc_gmsg.length));
		fc_i += fc_gmsg.length;
		gss_release_buffer(&fc_lmin_s, &fc_gmsg);
	}
	while (fc_msg_ctx);

	/* 添加空字符终止 */
	if (fc_i < fc_len)
		fc_s[fc_i] = '\0';
	else
	{
		elog(COMMERROR, "incomplete GSS error report");
		fc_s[fc_len - 1] = '\0';
	}
}

/*
 * 报告由 maj_stat/min_stat 描述的 GSSAPI 错误。
 *
 * errmsg 应该是一个已翻译的主要错误消息。
 * GSSAPI 信息作为 errdetail 附加。
 *
 * 错误始终以 elevel COMMERROR 报告；我们不敢试图
 * 发送给客户端，因为这可能会导致无限递归
 * 当 elog.c 尝试向客户端写入时。
 *
 * 为了避免内存分配，总错误大小被限制（每个主要和次要均为 128 字节）。
 * 目前已知的机制不会产生超出此限制的错误消息。
 */
void pg_GSS_error(const char *fc_errmsg,
			 OM_uint32 fc_maj_stat, OM_uint32 fc_min_stat)
{
	char		fc_msg_major[128],
				fc_msg_minor[128];

	/* 获取主要状态消息 */
	fc_pg_GSS_error_int(fc_msg_major, sizeof(fc_msg_major), fc_maj_stat, GSS_C_GSS_CODE);

	/* 获取机制次要状态消息 */
	fc_pg_GSS_error_int(fc_msg_minor, sizeof(fc_msg_minor), fc_min_stat, GSS_C_MECH_CODE);

	/*
	 * errmsg_internal，因为第一部分的翻译必须在调用此函数之前完成。
	 */
	ereport(COMMERROR,
			(errmsg_internal("%s", fc_errmsg),
			 errdetail_internal("%s: %s", fc_msg_major, fc_msg_minor)));
}
